Skip to content

Carry coarse label-source provenance into Under the Hood reports - #52

Closed
Pitchfork-and-Torch wants to merge 1 commit into
xai-org:mainfrom
Pitchfork-and-Torch:cursor/uth-label-source-provenance-dd47
Closed

Carry coarse label-source provenance into Under the Hood reports#52
Pitchfork-and-Torch wants to merge 1 commit into
xai-org:mainfrom
Pitchfork-and-Torch:cursor/uth-label-source-provenance-dd47

Conversation

@Pitchfork-and-Torch

@Pitchfork-and-Torch Pitchfork-and-Torch commented Aug 14, 2026

Copy link
Copy Markdown

Summary

Fixes #39.

README says Under the Hood should show whether labels were manually applied outside automated systems. The daily job already reads TweetSafetyLabelEvent.label but kept only timestamps; SafetyLabelSource was dropped, and the serving types had no field to carry it.

reportJson.source is one of four tokens:

  • automatedBotMakerAction
  • manualToolAction
  • llm ← a Grok/LLM union member, detected by productPrefix or getName plus the last non-empty . / $ segment (GrokAnnotation*), skipping a trailing synthetic $ and getSimpleName (can throw on Scala $ names), so this compiles if that case is absent from spam.rtf
  • unknown ← unset snapshot / tweet-flag / unmapped-source rows (serving clamp)

Jobs persist only automated | manual | llm after trim/lowercase. Unmapped, missing, leftover tokens, and tweet-flag rows stay unset (source = None is set explicitly on flag writes). Daily counts clamp the last-apply source before grouping. When an event apply and an unset snapshot apply are merged, the later timestamp wins; a persistable event source is kept only if the later row is a snapshot gap-fill (isSnapshot), not a later unmapped event. latestAsOf treats the newest asOf as a full rewrite of (user, authored day, label): it keeps every persistable source from that asOf and drops older asOf rows so a later sourced rewrite cannot sit beside an earlier unset row. The month MH writer reconstructs rows with named Scrooge fields and pattern-matches leftover same-day carried / removed (not best._4 / best._5). Serving clamps any other stored string to unknown, merges leftover rows that clamp to the same (label, source) by unioning days (larger carried/removed per day, then sum; groupBy.toList before flatMap so Map.flatMap cannot drop rows), pattern-matches that leftover group key as (name, source) rather than t._1 / t._2, and sorts that list by label then source so reportJson order is stable.

postLabelSource is a closed function (match + function closer before formatPercentage). Post-label about / effect look up by the raw label id, same as the account path; display name is only written to label.

Does not emit rule_id, actor_ldap, agent_tool, or VF-client type names. Snapshot and tweet-flag inputs stay unset (no invented source).

Based on current xai-org/x-algorithm main (c65aa179). Lane is under-the-hood/ only.

Test plan

  • Static review of the event → daily → month → reportJson path.
  • under-the-hood/ has no published build/test target in this snapshot; no job was executed.
  • Confirm Scrooge optional field source (ids 3 / 10) is backward-compatible with existing parquet/MH rows.
  • Confirm reportJson.source can only be automated | manual | llm | unknown.
  • Confirm snapshot/flag/unmapped/leftover-token rows coalesce to a single unknown row per label, including after daily count, latestAsOf, and reportJson day-union.
  • Confirm a later unset snapshot apply does not wipe an earlier persistable event source.
  • Confirm a later unmapped event apply does not inherit an earlier persistable source.
  • Confirm a newer asOf that fills source replaces older unset rows for the same (user, day, label) and does not emit both.
  • Confirm same-asOf automated and manual rows for one label both survive latestAsOf.
  • Confirm tweet-flag daily/backfill rows set source = None.
  • Confirm Automated / padded tokens normalize to the allowlist instead of unknown.
  • Confirm post-label rows are ordered by (label, source).
  • Confirm leftover serving groupBy keys (name, source) by pattern match, not t._1 / t._2.
  • Confirm leftover month same-day counts use pattern-matched carried / removed, not best._4 / best._5.
  • Confirm llm matching uses productPrefix or getName plus the last non-empty . / $ segment, not getSimpleName or String.split("$").
  • Confirm postLabelSource closes before formatPercentage.
  • Confirm postLabelAbout / postLabelEffect receive the raw label id, not the display name.

@kiri234-code

Copy link
Copy Markdown

Thank you for carrying coarse label-source provenance through the Under the Hood reporting path. This appears to address the reporting gap discussed in Issue #39.

I would like to clarify one important point about the scope of this change.

I have a real-world case where a post for which I voluntarily applied a content warning before publication appears in my Under the Hood report as NSFW_HIGH_PRECISION. The report shows one such post out of 73 total posts, with no account-level labels currently present.

This PR adds source to UthDailyPostLabel and UthPostLabelAggregate, but I do not see a corresponding change to safety-label-user-agg. Am I correct that this PR changes only how post-label provenance is reported, and does not change how those post labels are counted toward account-level NSFW labels?

If account aggregation evaluates NSFW_HIGH_PRECISION by label type without considering its source, an appropriately author-labeled post could still contribute to an account-level restriction in the same way as content that was left unlabeled and subsequently detected or reported.

Could you please clarify:

  1. Whether an author-applied content warning is represented as ToolAction / manual, or whether it reaches this reporting path without a mapped SafetyLabelSource and therefore appears as unknown.
  2. Whether safety-label-user-agg distinguishes author-applied labels from automated detections, reports, or X manual enforcement.
  3. If it does not, whether preserving an author_applied category—or otherwise making source information available to account aggregation—should be addressed in this PR or tracked separately.

The provenance added by this PR is valuable for transparency, but the most important practical question for affected users is whether responsible self-labeling can itself contribute to account-level visibility restrictions.

@Pitchfork-and-Torch

Copy link
Copy Markdown
Author

@kiri234-code You are reading the scope correctly.

This PR only changes the Under the Hood reporting path (under-the-hood/). It adds a coarse source on UthDailyPostLabel / UthPostLabelAggregate and the reportJson tokens automated | manual | llm | unknown. It does not edit safety-label-user-agg/ and it does not change how post labels are counted toward account-level labels.

On the three questions, from the published dump:

  1. Author-applied content warnings are not a separate author_applied token. UTH maps SafetyLabelSource.ToolAction to manual, BotMakerAction to automated, and a Grok/LLM union member (GrokAnnotation*) to llm. Snapshot, tweet-flag, unmapped, and missing sources stay unset and clamp to unknown in the report. Whether a pre-publish content warning is stored as ToolAction vs a tweet-flag / unmapped snapshot is not proven in this dump, so a self-labeled post can show up as manual or unknown depending on how that event was written.

  2. safety-label-user-agg does not distinguish source. The processor fetches baseTweetSafetyLabelMap and keeps labels.keys (label types only). Default rules trigger on NSFW_HIGH_PRECISION / SOFT_NSFW by name, then count matching posts in a window. No SafetyLabelSource check.

  3. Making source available to account aggregation (or an author_applied category) should be a separate PR. This one is the reporting gap in issue Under the Hood does not carry label-source provenance into the report, contrary to README:411 #39. Expanding it into serving/agg would mix classes.

One post labeled NSFW_HIGH_PRECISION with no account-level labels is consistent with the default agg windows (account NSFW_HIGH_PRECISION wants 3 matching posts in a 5-post window). UTH can still show that one post.

xAI owns whether self-labeling should be excluded from account restrictions. This PR does not claim to change that.

@kiri234-code

Copy link
Copy Markdown

@Pitchfork-and-Torch
Thank you very much for the detailed and clear explanation.

This confirms the distinction I wanted to understand: this PR affects only the Under the Hood reporting path, while the published account aggregation logic currently evaluates label types without checking their source.

I also understand that the published code does not establish whether an author-applied warning is written as ToolAction / manual, or enters through a tweet flag or unmapped path and becomes unknown. Therefore, whether self-labeling produces the relevant post label remains a separate unresolved question.

Your explanation of the default 3-in-5 aggregation window also clarifies why one NSFW_HIGH_PRECISION post can appear in Under the Hood without producing an account-level label.

This answers my questions about the scope of the PR and the behavior visible in the published code. I appreciate you taking the time to examine each point so carefully.

jnadeau207-collab added a commit to jnadeau207-collab/x-algorithm that referenced this pull request Sep 3, 2026
Carry logical post IDs through the daily and backfill post-label rows,
persist them in optional Thrift fields, aggregate the newest 1,000
distinct IDs per label into monthly rows, and emit them as strings in
reportJson alongside postIdsComplete.

IDs use the same logical-post identity (initialTweetId.getOrElse(tweetId))
as the existing carried counts, so an edited post chain stays one post in
both the count and the ID list.

Aggregation keeps the existing map-side combining: UthPostIds.merge is an
associative, commutative reduce that sums carried and removed exactly as
the previous sum did, and bounds the ID list at every merge. Peak reducer
memory per key stays bounded rather than growing with posts per key, and
the daily persisted rows carry the same bound as the monthly rows.

Field IDs 4 and 11 are intentional, leaving 3 and 10 for the
source-provenance fields proposed in xai-org#52.
TweetSafetyLabelEvent already has SafetyLabelSource (BotMaker vs Tool),
but the daily job dropped it and the report had no field to show whether
a label was applied manually. Persist a coarse category only — no
rule_id or actor_ldap — and emit it on each post-label row.

Fixes xai-org#39
@Pitchfork-and-Torch
Pitchfork-and-Torch force-pushed the cursor/uth-label-source-provenance-dd47 branch from 7b6ca47 to c65aa17 Compare September 8, 2026 23:16
@Pitchfork-and-Torch

Copy link
Copy Markdown
Author

Parking this intern-stack PR per operator GitHub cleanup (2026-09-08). Hunt notes remain local. Not a reject of the class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Under the Hood does not carry label-source provenance into the report, contrary to README:411

2 participants